<template>
	<view class="container">
		<button @click="startRecording" :disabled="isRecording">开始录音</button>
		<button @click="stopRecording" :disabled="!isRecording">停止录音</button>
		<!-- 显示转写结果 -->
		<view class="result-container" v-if="transcription">
			<text class="result-title">语音转写结果：</text>
			<text class="result-text">{{ transcription }}</text>
		</view>
		<!-- 状态和错误提示 -->
		<view v-if="statusMessage" class="status">{{ statusMessage }}</view>
		<view v-if="errorMessage" class="error">{{ errorMessage }}</view>
		<view v-if="!isSupported" class="error">您的浏览器不支持录音功能，请使用最新版Chrome、Edge或Firefox</view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			isRecording: false,
			mediaRecorder: null,
			audioChunks: [],
			transcription: '',
			statusMessage: '',
			errorMessage: '',
			isSupported: true,
			xunfeiSocket: null,
			recordingStartTime: null,
			recordingDuration: 0,
			timer: null,
			stream: null
		};
	},
	mounted() {
		this.isSupported = navigator.mediaDevices && MediaRecorder && MediaRecorder.isTypeSupported('audio/webm');
	},
	methods: {
		async startRecording() {
			if (!this.isSupported) return;
			try {
				this.resetUI();
				this.statusMessage = '正在启动录音...';
				// 获取麦克风权限
				this.stream = await navigator.mediaDevices.getUserMedia({
					audio: {
						sampleRate: 16000, // 科大讯飞推荐采样率
						channelCount: 1 // 单声道
					}
				});
				// 创建录音实例
				this.mediaRecorder = new MediaRecorder(this.stream, {
					mimeType: 'audio/webm;codecs=opus',
					audioBitsPerSecond: 16000 // 16kbps
				});
				this.audioChunks = [];
				this.transcription = '';
				// 收集录音数据
				this.mediaRecorder.ondataavailable = async (event) => {
					this.audioChunks.push(event.data);
					// 关键修改：转换音频格式为PCM后再发送
					const pcmData = await this.convertWebmToPcm(event.data);
					this.sendToXunfei(pcmData);
					// this.sendToXunfei(event.data); // 实时发送到转写服务
				};
				// 开始录音
				this.mediaRecorder.start(5000); // 每5秒发送一次数据
				this.isRecording = true;
				this.recordingStartTime = Date.now();
				this.recordingDuration = 0;
				// 计时器
				this.timer = setInterval(() => {
					this.recordingDuration = Math.floor((Date.now() - this.recordingStartTime) / 1000);
					this.statusMessage = `录音中... ${this.recordingDuration}秒`;
				}, 1000);
				// 连接科大讯飞服务
				await this.connectXunfei();
			} catch (error) {
				console.error('录音启动失败:', error);
				this.errorMessage = '无法访问麦克风或启动录音设备';
			}
		},
		stopRecording() {
			if (!this.isRecording) return;
			clearInterval(this.timer);
			this.mediaRecorder.stop();
			this.isRecording = false;
			this.statusMessage = '正在完成转写...';
			// 关闭麦克风
			if (this.stream) {
				this.stream.getTracks().forEach((track) => track.stop());
			}
			// 关闭WebSocket连接
			if (this.xunfeiSocket) {
				try {
					this.xunfeiSocket.close();
				} catch (e) {
					console.warn('关闭WebSocket时出错', e);
				}
				this.xunfeiSocket = null;
			}
		},
		resetUI() {
			this.transcription = '';
			this.statusMessage = '';
			this.errorMessage = '';
		},
		// 连接科大讯飞服务
		async connectXunfei() {
			return new Promise((resolve, reject) => {
				try {
					const authUrl = getApp().getWebSocketUrl();
					console.log('authUrl: ', authUrl);
					this.xunfeiSocket = new WebSocket(authUrl);
					this.xunfeiSocket.onopen = () => {
						console.log('socket-已连接到语音识别服务');
						this.statusMessage = '已连接到语音识别服务';
						// 修正后的初始化数据（严格按照API要求）
						const initData = {
							common: {
								app_id: '1d450eb0'
							},
							business: {
								language: 'zh_cn',
								domain: 'iat',
								accent: 'mandarin',
								vad_eos: 2000
								// 移除了audio_format, sample_rate, channel等非法字段
							},
							data: {
								status: 0,
								format: 'audio/L16;rate=16000',
								encoding: 'raw'
								// 移除了audio对象
							}
						};
						const initString = JSON.stringify(initData); // 确保正确序列化
						console.log('发送初始化数据:', initString);
						this.xunfeiSocket.send(initString); // 确保发送字符串数据
						resolve();
					};
					this.xunfeiSocket.onmessage = (event) => {
						console.log('socket-收到消息: ', event);
						const result = JSON.parse(event.data);
						this.processXunfeiResponse(result);
					};
					this.xunfeiSocket.onerror = (error) => {
						console.error('socket-科大讯飞连接错误:', error);
						this.errorMessage = '语音识别服务连接失败';
						reject(error);
					};
					this.xunfeiSocket.onclose = () => {
						console.error('socket-科大讯飞连接关闭');
						if (this.isRecording) {
							this.errorMessage = '语音识别连接意外断开';
						} else {
							this.statusMessage = '语音识别服务已断开';
						}
					};
				} catch (error) {
					console.error('连接科大讯飞失败:', error);
					this.errorMessage = '无法连接语音识别服务';
					reject(error);
				}
			});
		},
		// 处理科大讯飞响应
		processXunfeiResponse(event) {
			console.log('');
			// 确保正确处理不同格式的响应数据
			let response;
			try {
				// 有时event是MessageEvent，有时直接是JSON对象
				if (event instanceof MessageEvent) {
					response = JSON.parse(event.data);
				} else {
					response = event;
				}
			} catch (e) {
				return console.error('解析JSON失败', e);
			}
			if (response.code !== 0) {
				this.errorMessage = `语音识别错误: ${response.message || `代码${response.code}`}`;
				return console.error('科大讯飞错误:', response);
			}
			let newText = '';
			// 解析响应内容
			response.data.result?.ws?.forEach((wsItem) => {
				wsItem.cw?.forEach((cwItem) => {
					newText += cwItem.w;
				});
			});
			// 合并到当前转写结果
			if (response.data.status === 2) {
				// 最终结果
				if (newText) {
					this.transcription += newText;
				}
			} else if (newText) {
				// 中间结果
				// 只显示最新结果
				this.transcription = response.data.result.sn && response.data.result.sn > 1 ? this.transcription + newText : newText;
			}
		},
		async sendToXunfei(audioBlob) {
			if (!this.xunfeiSocket || this.xunfeiSocket.readyState !== WebSocket.OPEN) {
				return console.warn('WebSocket未准备好');
			}
			try {
				const pcmData = await this.convertWebmToPcm(audioBlob); // 尝试简化转换
				if (pcmData.length > 0) {
					this.xunfeiSocket.send(pcmData.buffer); // 发送转换后的PCM数据
				} else {
					// 备选方案：直接发送原始音频数据
					console.warn('发送原始音频数据作为备用方案');
					const arrayBuffer = await audioBlob.arrayBuffer();
					this.xunfeiSocket.send(arrayBuffer);
				}
				if (!this.isRecording) {
					const endData = JSON.stringify({ data: { status: 2, format: 'audio/L16;rate=16000', encoding: 'raw', audio: '' } });
					console.log('发送结束数据:', endData);
					this.xunfeiSocket.send(endData);
				}
			} catch (error) {
				console.error('发送音频数据失败: ', error);
			}
		},
		// 修改后的音频处理逻辑
		async convertWebmToPcm2(webmBlob) {
			try {
				// 直接读取二进制数据，避免使用AudioContext解码
				const arrayBuffer = await webmBlob.arrayBuffer();
				const audioData = new Uint8Array(arrayBuffer);
				// 添加调试日志
				console.log('音频数据大小:', audioData.length);
				// 简单方法：直接转换为Int16格式（实际应用中需要更复杂的转换）
				// 注意：这是一个简化版本，实际转换需要处理采样率和字节序
				const pcmData = new Int16Array(audioData.length / 2);
				for (let i = 0, j = 0; i < audioData.length; i += 2, j++) {
					// 合成16位整数
					const byte1 = audioData[i];
					const byte2 = audioData[i + 1];
					pcmData[j] = (byte2 << 8) | byte1;
				}
				return pcmData;
			} catch (error) {
				console.error('简化版音频格式转换失败:', error);
				// 备选方案：跳过转换直接发送原始数据
				console.warn('使用原始音频数据发送');
				return new Int16Array(0); // 返回空数据，但继续流程
			}
		},
		// 转换WebM到科大讯飞兼容的PCM格式
		async convertWebmToPcm(webmBlob) {
			try {
				// 1. 解码WebM格式
				const audioContext = new (window.AudioContext || window.webkitAudioContext)();
				const arrayBuffer = await webmBlob.arrayBuffer();
				const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
				// 2. 获取PCM数据
				const pcmData = audioBuffer.getChannelData(0); // 单声道
				// 3. 转换为Int16格式（科大讯飞要求）
				const length = pcmData.length;
				const buffer = new ArrayBuffer(length * 2);
				const view = new DataView(buffer);
				for (let i = 0; i < length; i++) {
					// 将浮点音频(-1到1)转换为16位整数(-32768到32767)
					const sample = Math.max(-1, Math.min(1, pcmData[i]));
					const int16Sample = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
					view.setInt16(i * 2, int16Sample, true); // 小端字节序
				}
				return new Int16Array(buffer);
			} catch (error) {
				console.error('音频格式转换失败:', error);
				throw new Error('音频格式转换失败');
			}
		},
		async processWebmAudio(webmBlob) {
			try {
				if (!webmBlob || typeof webmBlob !== 'object') {
					throw new Error('无效的音频数据');
				}
				// 使用兼容性方法读取音频数据
				const arrayBuffer = await this.getArrayBuffer(webmBlob);
				// 转换为PCM
				const pcmData = this.convertToPCM(arrayBuffer);
				return pcmData;
			} catch (error) {
				console.error('处理音频失败:', error);
				// 备用方案：直接返回原始数据
				if (webmBlob && webmBlob.size > 0) {
					console.warn('使用原始音频数据作为备用方案');
					const arrayBuffer = await this.getArrayBuffer(webmBlob);
					return new Uint8Array(arrayBuffer);
				}
				throw error;
			}
		},
		// 通用的ArrayBuffer获取方法（兼容所有浏览器）
		getArrayBuffer(blob) {
			return new Promise((resolve, reject) => {
				if (blob.arrayBuffer) {
					// 现代浏览器支持的API
					resolve(blob.arrayBuffer());
				} else {
					// 兼容旧版浏览器的FileReader方案
					const reader = new FileReader();
					reader.onload = () => resolve(reader.result);
					reader.onerror = () => reject(new Error('读取音频数据失败'));
					reader.readAsArrayBuffer(blob);
				}
			});
		},
		// 简单转换为PCM（根据你的需求自定义）
		convertToPCM(arrayBuffer) {
			const audioData = new Uint8Array(arrayBuffer);
			const pcmData = new Int16Array(audioData.length / 2);

			// 简单的16位转换逻辑（根据实际需求调整）
			for (let i = 0, j = 0; i < audioData.length; i += 2, j++) {
				pcmData[j] = (audioData[i + 1] << 8) | audioData[i];
			}

			return pcmData;
		}
	}
};
</script>

<style scoped>
.container {
	padding: 20px;
	text-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
}

button {
	margin: 10px;
	padding: 10px 20px;
	background-color: #4a9ff5;
	color: white;
	border: none;
	border-radius: 20px;
	font-size: 16px;
	min-width: 120px;
}

button:disabled {
	background-color: #cccccc;
}

.result-container {
	margin-top: 30px;
	padding: 15px;
	background-color: #f8f9fa;
	border-radius: 10px;
	width: 90%;
	max-width: 600px;
	min-height: 100px;
	text-align: left;
}

.result-title {
	font-weight: bold;
	color: #333;
	display: block;
	margin-bottom: 10px;
}

.result-text {
	font-size: 18px;
	color: #222;
	line-height: 1.6;
}

.status {
	margin-top: 15px;
	color: #666;
	font-size: 14px;
}

.error {
	margin-top: 15px;
	color: #e74c3c;
	font-weight: bold;
}
</style>
